package com.crazymaker.agent.demo.bytebuddy;

import com.crazymaker.agent.demo.aop.Listener;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.dynamic.scaffold.TypeValidation;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.utility.JavaModule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.instrument.Instrumentation;

import static net.bytebuddy.matcher.ElementMatchers.*;

public class CostTimeAgent {

    private static final Logger LOGGER = LoggerFactory.getLogger(CostTimeAgent.class);

    private final static String scanPackage = "com.crazymaker.circle.agent.biz";

    private final static String targetMethod = "sayHello";

//    private final static String implInterface = "org.springframework.cloud.gateway.filter.GlobalFilter";


    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println(">>>>> ByteBuddyAgentDemo - premain()");
        final ByteBuddy byteBuddy = new ByteBuddy().with(TypeValidation.of(false));
        new AgentBuilder.Default(byteBuddy)
                .type(nameStartsWith(scanPackage))
                .transform(new Transformer()) // update the byte code
                .with(new Listener(scanPackage))
                .installOn(inst);
    }

    /**
     *
     */
    private static class Transformer implements AgentBuilder.Transformer {
        @Override
        public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
                                                TypeDescription typeDescription,
                                                ClassLoader classLoader, JavaModule module) {
            if (typeDescription.getPackage().getActualName().equals(scanPackage)
//                    && typeDescription.getInterfaces().size() > 0
//                    && typeDescription.getInterfaces().get(0).getActualName().equals(implInterface)
                    ) {
                String targetClassName = typeDescription.getSimpleName();
                System.out.println("----------------------- target class:" + targetClassName);

                // 委托
                return builder.method(nameStartsWith(targetMethod)
                        .and(isPublic())).intercept(MethodDelegation.to(CostTimeAspect.class));

            }
            return builder;
        }
    }


}